#include "entities/character/Character.hh"
#include "input/InputCharacter.hh"
#include "constants/sounds.h"
#include "constants/common.hh"
#include "tools/Vector.hh"
#include "media/Sound.hh"

Character::Character()
        : _soundId("breathStand"),
          _soundTalking(""),
          _soundBreath(""),
          _soundInitSprint(""),
          _soundSprint("")
{
    // building sounds // sex dependent
    //  _soundStand = new Sound(SOUND_STAND_STR_FIXME);
    //  _soundWalk  = new Sound(SOUND_WALK_STR_FIXME);
    //  _soundRun   = new Sound(SOUND_RUN_STR_FIXME);

    // Building bodyParts Vector
    // for (int i = 0; i < NB_BODY_PARTS; ++i)
    // {
    //   // instaciate each bodyPart separately ?
    //   // indeed, Head as a listener, leg, shoulder
    //   _bodyParts[i] = new BodyPart;
    // }

    //_bodyParts[BODY_PART_HEAD] = new BodyPart;

    // load resources (samples / Animations, Model3D)

    updateCharacteristics();
}

Character::~Character()
{
    // rm sound resources (samples / Animations, Model3D)
}

// __________ Getters / Setters
float Character::getWeight()
{
    return _weight;
}

float Character::getHeight()
{
    return _height;
}

float Character::getHealth()
{
    return _globalHealth;
}
// __________ # end Getters / Setters

// __________ sounds
//void Character::updateListener()
//{
//	// diff left && right
//  	//_listenerCoords = _bodyParts[BODY_PART_HEAD].getCoords();
//}

// NOTE: footsteps sounds must be environment dependent (leafs, rocks. ...)
// but are not breath dependent

// defines && rename these csts
// shd reverse tests => default sound == stand, !run
bool Character::breath()
{
    // unsigned char soundId;
    //
    //  if (_breathLevel <= BREATH_LOW_LVL)
    //    soundId = SOUND_breathLevel_STAND;
    //
    //  else if (_breathLevel <= BREATH_MEDIUM_LVL)
    //    soundId = SOUND_BREATH_WALK;
    //
    //  else
    //    soundId = SOUND_BREATH_RUN;
    //
    //  _breathSound.updateSource(bodyParts[BODY_PART_HEAD].coords);
    //
    //  // sound already running, stop it
    //  if (_breathSound.status == OPENAL_PLAYING)
    //  {
    //	  // stop it
    //	  return;
    //  }
    //
    //  _breathSound.play(soundId);
    return true;
}

// __________ # end sound

void Character::updateHealth()
{
    _globalHealth = 0;

    for (unsigned char i = 0; i < NB_BODY_PARTS; ++i)
        _globalHealth += _bodyParts[i].getHealth();
}

void Character::updateWeight()
{
    _weight = 0;
    for (unsigned char i = 0; i < NB_BODY_PARTS; i++)
        _weight += _bodyParts[i].getCloth().getWeight();
}

// get from server
void Character::updateCharacteristics()
{
    for (unsigned char i = 0; i < NB_BODY_PARTS; i++)
    {
        _globalHealth += _bodyParts[i].getHealth();
        _weight += _bodyParts[i].getCloth().getWeight();
    }
}

// __________ Motion Methods

// sprint is about 30km/h (== 8.33 m/s)

// NOTE: need to overload '<' Vector operator
// cd be << 4 m per m && < 4 cm per cm (float cmp troubles)

// need interruption / impact point


// __________ #end Motion Methods

/*
 A	 O1     B	  O2
 .    .     .          .

 we have a velocity, a position, a direction
 A wants to go in B but will be stoped by O1
 */

// returns destination coords
//Vector Character::getMoveDestination(Vector direction)
//{
//  // for all Objects, browse them and check if theirs coords
//  // belong to Character path (need a limit)
//
//  while (_position < _velocity * direction)
//  {
//    _position += direction;
//    //if ()
//  }
//
//  // last meter, 10cm per 10cm
//  while (_position < _velocity * direction)
//    _position += 0.1 * direction;
//}
void Character::mouseControl()
{
// if we're in std mode (mouse: gun ctrl)
// else mouse: look
// cd use right click to switch...
}

bool Character::canShoot()
{
// add wall proximity management here
//  if (wall_proximity()) // shd be in Environement class
//    return false;

//return (_position != POSITION_CRAWLING || !_moving);

    return true;
}

bool Character::treatShot()
{
// if (tookShot())
// {
//  ** check death
//  ** moves character if necessary
//  ** drop inventory if necessary
//  ** plays a sound on hit
//  ** alter blind coeff
//  ** displays blood effect
//  ** \return is still alive || life lost
// }

// if close then blur effect

    return true;
}

bool Character::isDead()
{
    return (_globalHealth <= 0);
}

bool Character::isDown()
{
    return (_globalHealth <= HEALTH_MARGIN_DOWN);
}
